﻿#region Using namespaces

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

using QuickGraph;

using BOL.Models;

#endregion

namespace BOL.Apps.GeneNetworkBrowser
{
    /// <summary>
    /// Represent a gene relation.
    /// </summary>
    [Serializable]
    public class Relation : Edge<Gene>, ICloneable, IEquatable<Relation>, IFlagProvider<RelationTypes>, INotifyPropertyChanged
    {
        #region Private variables

        private double _score;

        #endregion

        #region Public properties

        [XmlIgnore]
        public double Score { get { return _score; } set { _score = value; } }

        #endregion

        #region Constructors

        public Relation(Gene gene1, Gene gene2, uint relationTypes)
            : base(gene1, gene2)
        {
            _relationTypes = (RelationTypes)relationTypes;
            _score = 0;
        }

        #endregion

        #region ICloneable implementation

        /// <summary>
        /// Creates an exact copy of current relation.
        /// </summary>
        /// <returns>Relation</returns>
        public Relation Clone()
        {
            return new Relation(Source.Clone(), Target.Clone(), (uint)_relationTypes);
        }

        /// <summary>
        /// Creates an exact copy of current relation as an object. 
        /// </summary>
        /// <returns>Relation</returns>
        object ICloneable.Clone()
        {
            return Clone();
        }

        #endregion

        //#region IVisible implementation

        //private bool _isVisible;

        //[Browsable(false)]
        //public bool IsVisible { get { return _isVisible; } set { _isVisible = value; } }

        //public void Show()
        //{
        //    _isVisible = true;
        //}

        //public void Hide()
        //{
        //    _isVisible = false;
        //}

        //#endregion

        //#region ISelected implementation

        //private bool _isSelected;

        //[Browsable(false)]
        //public bool IsSelected { get { return _isSelected; } set { _isSelected = value; } }

        //public void Select()
        //{
        //    _isSelected = true;
        //}

        //public void Deselect()
        //{
        //    _isSelected = false;
        //}

        //#endregion

        #region IFlagProvider<RelationTypes> implementation

        private RelationTypes _relationTypes;

        [Category("Information")]
        [DisplayName("Relation types")]
        [Description("Returns the type of the relation.")]
        [XmlIgnore]
        public RelationTypes RelationTypes { get { return _relationTypes; } }

        public void AddFlag(RelationTypes relationType) { _relationTypes |= relationType; }

        public void RemoveFlag(RelationTypes relationType) { _relationTypes ^= relationType; }

        public bool ContainsFlag(RelationTypes relationType)
        {
            if ((_relationTypes & relationType) != RelationTypes.None)
                return true;

            return false;
        }

        public void ClearFlag() { _relationTypes = RelationTypes.None; }

        #endregion

        #region IEquatable<Relation> implementation

        public bool Equals(Relation other)
        {
            return Source.Equals(other.Source) && Target.Equals(other.Target) && _relationTypes.Equals(other._relationTypes);
        }

        #endregion
        
        #region ISelectable implementation

        protected bool _isSelected;

        public bool IsSelected { get { return _isSelected; } }

        public void Select()
        {
            _isSelected = true;
            OnPropertyChanged("IsSelected");
        }

        public void Deselect()
        {
            _isSelected = false;
            OnPropertyChanged("IsSelected");
        }

        #endregion

        #region INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, e);
        }

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        protected void OnPropertyChanged(params string[] propertyNames)
        {
            if (propertyNames == null)
                throw new ArgumentNullException("PropertyNames cannot be null.");

            foreach (var propertyName in propertyNames)
                OnPropertyChanged(propertyName);
        }

        #endregion

        #region Object overriden

        public override int GetHashCode()
        {
            return Source.GetHashCode() ^ Target.GetHashCode() ^ (int)_relationTypes;
        }

        public override bool Equals(object obj)
        {
            if (obj == null) return base.Equals(obj);

            if (!(obj is Relation))
                throw new InvalidCastException("The 'obj' argument is not a Relation object.");
            else
                return Equals(obj as Relation);
        }

        public override string ToString()
        {
            return String.Format("{0}-{1}", Source, Target);
        }

        #endregion
    }
}
